# app/services/oss_service.py

import os
import uuid
import aiohttp
import requests
import oss2
import json  
import logging
from oss2.models import PartInfo
from app.core.config import settings
from aliyunsdkcore.client import AcsClient  
from aliyunsdksts.request.v20150401.AssumeRoleRequest import AssumeRoleRequest  

# 初始化 OSS Bucket
auth = oss2.Auth(settings.OSS_ACCESS_KEY_ID, settings.OSS_ACCESS_KEY_SECRET)
bucket = oss2.Bucket(auth, settings.OSS_ENDPOINT, settings.OSS_BUCKET_NAME)
client = AcsClient(  
    settings.OSS_ACCESS_KEY_ID,  
    settings.OSS_ACCESS_KEY_SECRET,  
    'cn-hangzhou'  # STS服务的地域  
)  
async def upload_file_to_oss(local_filename, file_extension='mp4'):
    """
    上传本地文件到 OSS，返回文件的访问 URL 和 oss_key。
    """
    try:
        # 生成唯一的文件名
        unique_filename = str(uuid.uuid4())[:8]
        oss_key = f'xiaorui/{unique_filename}.{file_extension}'

        # 获取文件大小
        total_size = os.path.getsize(local_filename)
        # determine_part_size方法用于确定分片大小
        part_size = oss2.determine_part_size(total_size, preferred_size=100 * 1024)

        # 初始化分片上传
        upload_id = bucket.init_multipart_upload(oss_key).upload_id

        parts = []

        # 逐个上传分片
        with open(local_filename, 'rb') as fileobj:
            part_number = 1
            offset = 0
            while offset < total_size:
                num_to_upload = min(part_size, total_size - offset)
                result = bucket.upload_part(
                    oss_key, upload_id, part_number,
                    oss2.SizedFileAdapter(fileobj, num_to_upload)
                )
                parts.append(PartInfo(part_number, result.etag))

                offset += num_to_upload
                part_number += 1

        # 完成分片上传
        bucket.complete_multipart_upload(oss_key, upload_id, parts)

        # 构建文件的访问 URL
        file_url = f'https://{settings.OSS_BUCKET_NAME}.{settings.OSS_ENDPOINT.replace("https://", "")}/{oss_key}'
        return file_url, oss_key  # 返回文件URL和oss_key
    except Exception as e:
        logging.error(f"上传文件到 OSS 时出错：{e}")
        raise

async def download_file(url, local_filename):
    """
    从指定 URL 下载文件到本地。
    """
    try:
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                if response.status == 200:
                    with open(local_filename, 'wb') as file:
                        while True:
                            chunk = await response.content.read(8192)
                            if not chunk:
                                break
                            file.write(chunk)
                else:
                    raise Exception(f"Failed to download file: {response.status}")
    except Exception as e:
        logging.error(f"下载文件时出错：{e}")
        raise

async def generate_signed_url(object_name, expiration=60):
    """
    生成阿里云OSS预签名URL，用于获取视频的第一帧图片。
    """
    try:
        # 视频截图参数
        style = "video/snapshot,t_0,f_jpg,w_800,h_600"  # t_0表示第一帧

        # 生成签名URL
        signed_url = bucket.sign_url('GET', object_name, expiration, params={'x-oss-process': style})
        return signed_url
    except Exception as e:
        logging.error(f"生成签名URL时出错：{e}")
        raise

async def upload_image_to_oss(local_filename, file_extension='jpg'):
    oss_file_url, oss_key = await upload_file_to_oss(local_filename, file_extension=file_extension)
    return oss_file_url, oss_key


# 获取临时验证秘钥
async def get_sts_token():  
    request = AssumeRoleRequest()  
    request.set_accept_format('json')  
    request.set_RoleArn(settings.OSS_ARN)  
    request.set_RoleSessionName(settings.OSS_SESSION_NAME)  
    request.set_DurationSeconds(3000)  

    response = client.do_action_with_exception(request)  
    response_json = json.loads(response)  
    return {  
        'accessKeyId': response_json['Credentials']['AccessKeyId'],  
        'accessKeySecret': response_json['Credentials']['AccessKeySecret'],  
        'securityToken': response_json['Credentials']['SecurityToken'],
        'durationSeconds': response_json['Credentials']['Expiration']
    }  